package com.tarry.io.file.archive;

import cn.hutool.core.util.ZipUtil;
import de.innosystec.unrar.Archive;
import de.innosystec.unrar.NativeStorage;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
public class FileDecompressUtil {
    private final static List<String> ZIP_TYP = Arrays.asList("rar","zip");

    private FileDecompressUtil () {

    }

    /**
     *
     */
    public static void decompress (FileInfo resourceFile, String targetPath) {
        Objects.requireNonNull(resourceFile);
        if (FileDecompressUtil.isNotCompressFile(resourceFile.getType())){
            log.error("file info {}", resourceFile);
            throw new RuntimeException("unsupported file type");
        }

        switch (resourceFile.getType().toLowerCase()) {
            case "zip" :
                FileDecompressUtil.unZipFile(resourceFile.getPath().toFile(), targetPath);
                break;
            case "rar" :
                FileDecompressUtil.unRarFile(resourceFile.getPath().toFile(), targetPath);
                break;
            default:
                log.warn("unknown this type {}", resourceFile.getType());
        }

    }

    public static boolean isNotCompressFile(String type){
        return ! FileDecompressUtil.isZip(type);
    }

    /**
     * 判断文件后缀名是否为压缩文件
     * @param fileSuffix 文件后缀
     * @return true or false
     */
    private static boolean isZip(String fileSuffix) {
        return ZIP_TYP.contains(fileSuffix);
    }

    /**
     *  对zip文件进行解压
     * @param file 需要解压对文件
     * @param targetPath 解压到指定目录
     */
    private static void unZipFile(File file, String targetPath) {
        try {
            ZipUtil.unzip(file, Paths.get(targetPath).toFile(), Charset.forName("GBK"));
        }catch (Exception e){
            log.error("{}  unzip error:", file.getName(),e);
        }
    }

    /**
     * 将rar压缩文件解压到临时目录，并返回目录地址
     * @param file file obj
     * @return file path
     */
    private static void unRarFile(File file, String targetPath) throws RuntimeException {
        Archive archive = null;
        FileOutputStream fileOutputStream = null;
        try {
            archive = new Archive(new NativeStorage(file));
            FileHeader fileHeader = archive.nextFileHeader();
            while (Objects.nonNull(fileHeader)) {
                if ( !fileHeader.isDirectory() ) {
                    // 相对路径名称
                    String compressFileName = fileHeader.getFileNameW();
                    // 解压文件名称
                    if (Objects.equals("/", File.separator)) { // Linux 系统
                        compressFileName = compressFileName.replace("\\", File.separator );
                    }
                    String dir = new StringBuffer(targetPath).append(compressFileName.substring(compressFileName.lastIndexOf(File.separator))).toString();
                    // 解压缩文件
                    fileOutputStream = new FileOutputStream(dir);
                    archive.extractFile(fileHeader, fileOutputStream);
                    fileOutputStream.close();
                    fileOutputStream = null;
                }
                fileHeader = archive.nextFileHeader();
            }
        } catch (RarException | IOException e) {
            log.error("unzip rar error:", e);
        } finally {
            if (Objects.nonNull(fileOutputStream)) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (Objects.nonNull(archive)){
                try {
                    archive.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
